package com.auntvt.timo.jpax.springbootstarter.primarykey;

import com.auntvt.timo.jpax.core.utils.SpringContextUtil;
import com.auntvt.timo.jpax.springbootstarter.config.properties.JpaxPrimaryKeyProperties;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import java.io.Serializable;
import java.util.Properties;

/**
 * jpax主键生成匹配器，可灵活配置主键生成规则
 *
 * @author 小懒虫 <auntvt@163.com>
 * @date 2021/5/27
 */
public class JpaxGeneratorMatch implements IdentifierGenerator, Configurable {

    /**
     * jpax匹配器名称
     */
    public static final String NAME = "jpax-match";

    /**
     * 类的包路径名称
     */
    public static final String PATH = "com.auntvt.timo.jpax.springbootstarter.primarykey.JpaxGeneratorMatch";

    /**
     * 初始化DefaultIdentifierGeneratorFactory工厂
     */
    private static DefaultIdentifierGeneratorFactory jpaGeneratorFactory = new DefaultIdentifierGeneratorFactory();

    /**
     * 主键生成器对象
     */
    private IdentifierGenerator generator;

    /**
     * 初始化配置
     */
    private Type type;

    /**
     * 初始化配置
     */
    private Properties params;

    @Override
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
        this.type = type;
        this.params = params;
    }

    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
        if (generator == null) {
            // 获取默认主键生成策略
            JpaxPrimaryKeyProperties primaryKeyProperties = SpringContextUtil.getBean(JpaxPrimaryKeyProperties.class);
            String defaultStrategy = primaryKeyProperties.getDefaultStrategy();

            try {
                // 获取带有{JpaxStrategy.PREFIX}前缀的自定义主键生成策略
                generator = SpringContextUtil.getBean(JpaxStrategy.PREFIX + defaultStrategy, IdentifierGenerator.class);
            } catch (NoSuchBeanDefinitionException e) {
                try {
                    // 获取自定义主键生成策略-无前缀
                    generator = SpringContextUtil.getBean(defaultStrategy, IdentifierGenerator.class);
                } catch (NoSuchBeanDefinitionException e1) {
                    // 获取jpa内置的主键生成策略
                    generator = jpaGeneratorFactory.createIdentifierGenerator(defaultStrategy, type, params);
                }
            }
        }

        return generator.generate(session, object);
    }
}
